package com.atguigu.gulimall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.product.vo.Catelog2Vo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.product.dao.CategoryDao;
import com.atguigu.gulimall.product.entity.CategoryEntity;
import com.atguigu.gulimall.product.service.CategoryService;
import org.springframework.util.StringUtils;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Autowired
    StringRedisTemplate redisTemplate;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }


    @Override
    public R listTree() {
        //ToDo:查询出所有的菜单
        List<CategoryEntity> categoryEntities = baseMapper.selectList(null);
        //
        List<CategoryEntity> catLevel1 = categoryEntities.stream().filter(categoryEntity -> {
            //筛选出顶级父菜单（等级为1的）
            return categoryEntity.getCatLevel().equals(1);
        }).map(categoryEntity -> {
            //添加子菜单
            categoryEntity.setChildrens(getChildrens(categoryEntity, categoryEntities));
            return categoryEntity;
        }).sorted((e1, e2) -> {
            return (e1.getSort() == null ? 0 : e1.getSort()) - (e2.getSort() == null ? 0 : e1.getSort());
        }).collect(Collectors.toList());


        return R.ok().put("tree", catLevel1);
    }

    @Override
    public void removeMenus(List<Long> asList) {
        //ToDo: 删除之前检查菜单有没有被别的地方引用
        baseMapper.deleteBatchIds(asList);
    }

    @Override
    public Long[] getCatelogFullPath(Long catelogId) {
        ArrayList<Long> catelogs = new ArrayList<>();
        //查找当前分类的详情
        List<Long> list = this.getParentPath(catelogId, catelogs);
        //倒序
        Collections.reverse(list);
        Long[] array = list.toArray(new Long[list.size()]);
        return array;

    }


    public List<Long> getParentPath(Long catId, List<Long> catelogs) {
        catelogs.add(catId);
        CategoryEntity entity = this.getById(catId);
        if (entity.getParentCid() != 0) {
            this.getParentPath(entity.getParentCid(), catelogs);
        }
        return catelogs;
    }


    /**
     * 筛选出当前菜单的所有子菜单
     *
     * @param tempEntity       当前菜单
     * @param categoryEntities 所有菜单
     * @return
     */
    public List<CategoryEntity> getChildrens(CategoryEntity tempEntity, List<CategoryEntity> categoryEntities) {
        List<CategoryEntity> childrens = categoryEntities.stream().filter(categoryEntity -> {
            return categoryEntity.getParentCid().equals(tempEntity.getCatId());
        }).map(categoryEntity -> {
            categoryEntity.setChildrens(getChildrens(categoryEntity, categoryEntities));
            return categoryEntity;
        }).sorted((e1, e2) -> {
            return (e1.getSort() == null ? 0 : e1.getSort()) - (e2.getSort() == null ? 0 : e1.getSort());
        }).collect(Collectors.toList());
        return childrens;
    }


    /**
     * 查询所有一级分类
     *
     * @return
     */
    @Cacheable(value = "Category",key = "#root.methodName")
    @Override
    public List<CategoryEntity> getAllLevel1() {
        System.out.println("缓存未命中，进入查询方法。。。");
        QueryWrapper<CategoryEntity> wrapper = new QueryWrapper<>();
        //表中创建的索引为parent_cid
        wrapper.eq("parent_cid", "0");
        List<CategoryEntity> categoryEntityList = baseMapper.selectList(wrapper);
        System.out.println("查询到的categoryEntityList:"+categoryEntityList);
        return categoryEntityList;
    }


    /**
     * 渲染二级分类和三级分类的数据
     */
    @Override
    public Map<String, List<Catelog2Vo>> getLevel23Data() {

        //本地锁
        synchronized (this) {
            //双重校验（目的是为了等待的线程抢到了锁以后，进入方法内部，首先去缓冲中获取一下，看看前一个线程有没有将结果放到缓存中）
            String res = redisTemplate.opsForValue().get("cateLogs");
            if (StringUtils.isEmpty(res)) {
                //确实没有
                System.out.println("查询数据库。。。。。。");
                //查询所有的分类数据
                List<CategoryEntity> allCategory = this.getAllCategory();
                //查出所有的一级分类数据
                List<CategoryEntity> level1List = getParent_cid(allCategory, 0L);
                //对所有的一级分类转换成map，key为分类的编号，value组装为vatelog2Vo的数据
                Map<String, List<Catelog2Vo>> listMap = null;
                if (level1List != null) {

                    Map<String, List<Catelog2Vo>> finalListMap = listMap;
                    listMap = level1List.stream().collect(Collectors.toMap(k -> {
                        return k.getCatId().toString();
                    }, v -> {
                        //当前一级分类下的所有二级分类的数据
                        List<CategoryEntity> level2List = getParent_cid(allCategory, v.getCatId());
                        List<Catelog2Vo> collect = null;
                        if (level2List != null) {
                            collect = level2List.stream().map(item -> {
                                //组装catelog2Vo的数据
                                Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, item.getCatId().toString(), item.getName());
                                //查询当前二级分类下的三级分类的数据
                                List<CategoryEntity> level3List = getParent_cid(allCategory, item.getCatId());
                                List<Catelog2Vo.catalog3Vo> catalog3List = level3List.stream().map(lv3 -> {
                                    Catelog2Vo.catalog3Vo catalog3Vo = new Catelog2Vo.catalog3Vo(lv3.getCatId().toString(), item.getCatId().toString(), lv3.getName());
                                    return catalog3Vo;
                                }).collect(Collectors.toList());
                                catelog2Vo.setCatalog3List(catalog3List);

                                return catelog2Vo;
                            }).collect(Collectors.toList());
                        }

                        return collect;
                    }));
                }

                //保证原子性，查完以后将结果放入缓存中
                String s = JSON.toJSONString(listMap);
                redisTemplate.opsForValue().set("cateLogs", s);

                return listMap;

            } else {
                TypeReference<Map<String, List<Catelog2Vo>>> reference = new TypeReference<Map<String, List<Catelog2Vo>>>() {
                };
                Map<String, List<Catelog2Vo>> object = JSON.parseObject(res, reference);
                return object;
            }


        }


    }


    public Map<String, List<Catelog2Vo>> getCatelogFromCache() {
        //从缓存中获取分类数据
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String res = ops.get("cateLogs");
        //如果缓存中没有，将数据库中查出来的数据返回。并且在缓存中放一份
        if (StringUtils.isEmpty(res)) {
            System.out.println("缓存没有命中，将要去查数据库。。。");
            Map<String, List<Catelog2Vo>> data = this.getLevel23Data();
//            String cateLogs = JSON.toJSONString(data);
//            ops.set("cateLogs",cateLogs);
            return data;
        } else {
            System.out.println("缓存命中。。。直接返回数据。。。。");
            //缓存中有的直接返回缓存中的分类数据
            TypeReference<Map<String, List<Catelog2Vo>>> reference = new TypeReference<Map<String, List<Catelog2Vo>>>() {
            };
            Map<String, List<Catelog2Vo>> object = JSON.parseObject(res, reference);
            return object;

        }
    }


    private List<CategoryEntity> getParent_cid(List<CategoryEntity> categoryEntities, Long parentCid) {
        List<CategoryEntity> entityList = categoryEntities.stream().filter(categoryEntity -> {
            return categoryEntity.getParentCid().equals(parentCid);
        }).collect(Collectors.toList());

        return entityList;
//        return baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", parentCid));
    }


    public List<CategoryEntity> getAllCategory() {
        List<CategoryEntity> categoryEntityList = baseMapper.selectList(null);
        return categoryEntityList;
    }


    /**
     * 整合SpringCache
     * @return
     */
    @Cacheable(value = "Category" ,key = "'getLevel23DataWithSpringCache'")
    @Override
    public Map<String, List<Catelog2Vo>> getLevel23DataWithSpringCache() {

        //本地锁
        synchronized (this) {

                //确实没有
                System.out.println("查询数据库。。。。。。");
                //查询所有的分类数据
                List<CategoryEntity> allCategory = this.getAllCategory();
                //查出所有的一级分类数据
                List<CategoryEntity> level1List = getParent_cid(allCategory, 0L);
                //对所有的一级分类转换成map，key为分类的编号，value组装为vatelog2Vo的数据
                Map<String, List<Catelog2Vo>> listMap = null;
                if (level1List != null) {

                    Map<String, List<Catelog2Vo>> finalListMap = listMap;
                    listMap = level1List.stream().collect(Collectors.toMap(k -> {
                        return k.getCatId().toString();
                    }, v -> {
                        //当前一级分类下的所有二级分类的数据
                        List<CategoryEntity> level2List = getParent_cid(allCategory, v.getCatId());
                        List<Catelog2Vo> collect = null;
                        if (level2List != null) {
                            collect = level2List.stream().map(item -> {
                                //组装catelog2Vo的数据
                                Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, item.getCatId().toString(), item.getName());
                                //查询当前二级分类下的三级分类的数据
                                List<CategoryEntity> level3List = getParent_cid(allCategory, item.getCatId());
                                List<Catelog2Vo.catalog3Vo> catalog3List = level3List.stream().map(lv3 -> {
                                    Catelog2Vo.catalog3Vo catalog3Vo = new Catelog2Vo.catalog3Vo(lv3.getCatId().toString(), item.getCatId().toString(), lv3.getName());
                                    return catalog3Vo;
                                }).collect(Collectors.toList());
                                catelog2Vo.setCatalog3List(catalog3List);

                                return catelog2Vo;
                            }).collect(Collectors.toList());
                        }

                        return collect;
                    }));
                }

                return listMap;



        }


    }



}